package com.chen.service.impl;

import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.RandomUtil;
import com.alicp.jetcache.Cache;
import com.alicp.jetcache.anno.CacheType;
import com.alicp.jetcache.anno.CreateCache;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.chen.domain.CashRecharge;
import com.chen.domain.CashRechargeAuditRecord;
import com.chen.domain.Coin;
import com.chen.dto.AdminBankDto;
import com.chen.dto.AdminUserDto;
import com.chen.dto.UserBankDto;
import com.chen.enums.AccountEnums;
import com.chen.fegin.AdminBankFegin;
import com.chen.fegin.AdminUserFegin;
import com.chen.fegin.UserBankFegin;
import com.chen.mapper.CashRechargeMapper;
import com.chen.model.CoinModel;
import com.chen.service.*;
import com.chen.utils.UserUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
public class CashRechargeServiceImpl extends ServiceImpl<CashRechargeMapper, CashRecharge> implements CashRechargeService {


    @Autowired
    private AdminBankFegin adminBankFegin;

    @Autowired
    private RedisTemplate<String,Object> redisTemplate;

    @Resource
    private CashRechargeMapper cashRechargeMapper;

    private final Snowflake snowflake = new Snowflake(2, 1);


    @CreateCache(name = "CASH_RECHARGE_LOCK:", expire = 100, cacheType = CacheType.BOTH)
    private Cache<String, String> cache;


    @Resource
    private AdminUserFegin adminUserFegin;

    @Autowired
    private CoinService coinService;

    @Autowired
    private AccountService accountService;

    @Autowired
    private RecordsService<CashRecharge> rechargeRecordsService;

    @Autowired
    private CashRechargeAuditRecordService cashRechargeAuditRecordService;

    @Override
    public Page<CashRecharge> pageForList(Page<CashRecharge> page,
                                          Long coinId,
                                          Long userId,
                                          String userName,
                                          String mobile,
                                          Byte status,
                                          String numMax,
                                          String numMin,
                                          String startTime,
                                          String endTime) {
        try {


            RecordsServiceImpl.SearchRecords searchRecords = new RecordsServiceImpl.SearchRecords();

            searchRecords.setCoinId(coinId);
            searchRecords.setUserId(userId);
            searchRecords.setUserName(userName);
            searchRecords.setMobile(mobile);
            searchRecords.setStatus(status);

            Map<RecordsServiceImpl.SearchRecords.BetweenDataEnum, Map<String, RecordsServiceImpl.SearchRecords.LimitRecords>> betweenData = new HashMap<>();

            //设置金钱区间
            Map<String, RecordsServiceImpl.SearchRecords.LimitRecords> limitRecordsMap = new HashMap<>();
            limitRecordsMap.put("num", RecordsServiceImpl.SearchRecords.LimitRecords.builder().min(numMin).max(numMax).build());
            betweenData.put(RecordsServiceImpl.SearchRecords.BetweenDataEnum.AMOUNT, limitRecordsMap);

            //设置金钱区间
            limitRecordsMap = new HashMap<>();
            limitRecordsMap.put("created", RecordsServiceImpl.SearchRecords.LimitRecords.builder().min(startTime).max(endTime).build());
            betweenData.put(RecordsServiceImpl.SearchRecords.BetweenDataEnum.TIME, limitRecordsMap);


            searchRecords.setBetweenData(betweenData);

            return rechargeRecordsService.findData(page, cashRechargeMapper, searchRecords);
        } catch (InvocationTargetException | NoSuchMethodException | NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }
        return page;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void checkRecharge(CashRecharge cashRecharge) {
        //1 当一个员工审核时,另一个员工不能在审核
        //CASH_RECHARGE_LOCK:1231123
        cache.tryLockAndRun(cashRecharge.getId() + "", 300, TimeUnit.SECONDS, () -> {
            //审核通过

            if (cashRecharge.getStatus() == 1) {
                //修改原用的充值订单数据 订单的完成时间 状态
                CashRecharge cashRechargex = getById(cashRecharge);
                if (cashRechargex == null) {
                    throw new IllegalArgumentException("订单数据错误");
                }
                cashRechargex.setLastTime(new Date());
                cashRechargex.setStatus(cashRecharge.getStatus());
                cashRechargex.setAuditRemark(cashRecharge.getRemark());
                updateById(cashRechargex);

                //给该用户账户增加
                QueryWrapper<Coin> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("name", "CNY");
                List<Coin> list = coinService.list(queryWrapper);
                if (CollectionUtils.isEmpty(list)) {
                    throw new IllegalArgumentException("CNY未配置");
                }

                //添加资金流水
                accountService.transfer(list.get(0).getId(), cashRechargex.getCoinId(),
                        null, cashRechargex.getUserId(), cashRechargex.getId(),
                        AccountEnums.recharge_into.getCode(), cashRechargex.getNum(),
                        cashRechargex.getFee(), cashRechargex.getAuditRemark());

                //充值的流水
                CashRechargeAuditRecord cashRechargeAuditRecord = new CashRechargeAuditRecord();
                cashRechargeAuditRecord.setOrderId(cashRechargex.getId());
                Long userId = UserUtil.getUser();
                cashRechargeAuditRecord.setAuditUserId(userId);

                //远程调用查询管理员的名称
                Map<Long, AdminUserDto> adminUser = adminUserFegin.getAdminUser(Arrays.asList(userId));
                AdminUserDto adminUserDto = adminUser.get(userId);
                cashRechargeAuditRecord.setAuditUserName(adminUserDto.getUsername());
                cashRechargeAuditRecord.setCreated(new Date());
                cashRechargeAuditRecord.setId(snowflake.nextId());
                cashRechargeAuditRecord.setRemark(cashRecharge.getRemark());
                cashRechargeAuditRecord.setStep((byte) (cashRechargex.getStep() + (byte) 1));
                cashRechargeAuditRecord.setStatus((byte) 1);
                //保存流水
                cashRechargeAuditRecordService.save(cashRechargeAuditRecord);
            } else {
                //审核 失败的情况
                saveCashRecgarge(cashRecharge);

            }
        });
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public CashRecharge buy(CoinModel coinModel) {

        CashRecharge cashRecharge = new CashRecharge();
        cashRecharge.setStatus((byte)0);

        //远程调用会员服务查询用户银行卡
        AdminBankDto userBank = adminBankFegin.getAdminBank();
        cashRecharge.setBankCard(userBank.getBankCard());
        cashRecharge.setBankName(userBank.getBankName());
        cashRecharge.setName(userBank.getName());

        cashRecharge.setCoinId(Long.parseLong(coinModel.getCoinId()));
        Coin byId = coinService.getById(coinModel.getCoinId());
        cashRecharge.setCoinName(byId.getName());
        cashRecharge.setFee(BigDecimal.ZERO);
        cashRecharge.setFeecoin(coinModel.getCoinId());

        //手动计算当前汇率

        Object buyObject = redisTemplate.opsForHash().get("CNY", "CNY2USDT");
        if(buyObject == null){
            throw new IllegalArgumentException("请设置人民币充值GCN换算费率");
        }
        //成交数量
        cashRecharge.setMum(new BigDecimal(coinModel.getNum()).multiply(new BigDecimal(buyObject.toString())));
        cashRecharge.setNum(new BigDecimal(coinModel.getNum()));
        cashRecharge.setUserId(UserUtil.getUser());
        cashRecharge.setType("bank");
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        String format = sdf.format(new Date());
        format = format + System.currentTimeMillis()+RandomUtil.randomNumbers(4);
        cashRecharge.setTradeno(format);
        cashRecharge.setRemark(RandomUtil.randomNumbers(6));
        cashRecharge.setCreated(new Date());
        cashRecharge.setLastUpdateTime(new Date());
        cashRecharge.setStep((byte)1);
        save(cashRecharge);

        return cashRecharge;
    }

    private void saveCashRecgarge(CashRecharge cashRecharge) {
        CashRecharge cashRechargex = getById(cashRecharge);
        cashRechargex.setLastTime(new Date());
        cashRechargex.setStatus(cashRecharge.getStatus());
        cashRechargex.setAuditRemark(cashRecharge.getRemark());
        updateById(cashRechargex);

        CashRechargeAuditRecord cashRechargeAuditRecord = new CashRechargeAuditRecord();
        cashRechargeAuditRecord.setOrderId(cashRechargex.getId());
        Long userId = UserUtil.getUser();
        cashRechargeAuditRecord.setAuditUserId(userId);


        Map<Long, AdminUserDto> adminUser = adminUserFegin.getAdminUser(Arrays.asList(userId));
        AdminUserDto adminUserDto = adminUser.get(userId);
        cashRechargeAuditRecord.setAuditUserName(adminUserDto.getUsername());
        cashRechargeAuditRecord.setCreated(new Date());
        cashRechargeAuditRecord.setId(snowflake.nextId());
        cashRechargeAuditRecord.setRemark(cashRecharge.getRemark());
        cashRechargeAuditRecord.setStep((byte) 1);
        cashRechargeAuditRecord.setStatus((byte) 1);

        cashRechargeAuditRecordService.save(cashRechargeAuditRecord);
    }


}
